package sprites;

import interfaces.IPaintable;
import interfaces.IUpdatable;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.HashSet;
import java.util.Set;
import javax.swing.ImageIcon;

/**
 * Abstract class that creates to be extended by all kinds of sprites in
 * GameEnvironment.
 * @author Amay
 *
 */
public abstract class Sprite implements IUpdatable, IPaintable {

    private Image myImage;
    private int myWidth;
    private int myHeight;
    private int myHP;
    private Point myPosition;
    private Set<Class> myCollidableTypes;
    private String myImageLoc;

    private final String DEFAULT_IMAGE_LOC = "../resources/defaultSprite.jpg";
    private final Point DEFAULT_POSITION = new Point(100, 100);
    private final int DEFAULT_IMPACT = 0;
    private final int DEFAULT_HP = 1;

    /**
     * Constructor to initialize Sprite with default image.
     */
    public Sprite () {
        myImageLoc = DEFAULT_IMAGE_LOC;
        initSprite();

    }

    /**
     * Constructor to initialize a sprite with the image at imageLoc 
     * @param imageLoc string location of image to be loaded
     */
    public Sprite (String imageLoc) {
        myImageLoc = imageLoc;
        initSprite();
    }

    /**
     * Constructor to initialize a Sprite with the same parameters as Sprite s.
     * @param s Sprite to be created
     */
    public Sprite (Sprite s) {
        myImageLoc = s.myImageLoc;
        initSprite();
        myPosition = new Point(s.getPosition());
        myHP = s.getHP();
        myCollidableTypes = new HashSet<Class>(s.getCollidableTypes());
    }

    @Override
    public abstract void update ();

    /**
     * Determines how the Sprite should react if there is a collision with another sprite.
     * @param s Sprite with which this will be colliding
     */
    public abstract void collisionHandle (Sprite s);

    @Override
    public Image getImage () {
        return myImage;
    }

    /**
     * Sets initial position of sprite to point p.
     * @param p Point at which sprite is created
     */
    public void configurePosition (Point p) {
        myPosition = p;
    }

    /**
     * Sets initial health value of the sprite.
     * @param healthPoints amount of health given to the sprite
     */
    public void configureHP (int healthPoints) {
        myHP = healthPoints;
    }

    // If this Sprite should react to the Sprite type passed in as a parameter
    /**
     * Adds sprite type to list of sprite types that current sprite can collide with.
     * @param s Sprite that this can collide with 
     * @throws ClassNotFoundException thrown when argument is not a sprite
     */
    public void addCollidableSprite (Sprite s) throws ClassNotFoundException {
        myCollidableTypes.add(s.getClass());
    }

    /**
     * Returns the bounds of the sprite's image.
     * @return Rectangle bounds of sprite
     */
    public Rectangle getRect () {
        return new Rectangle((int) myPosition.getX(), (int) myPosition.getY(), myWidth, myHeight);
    }

    @Override
    public Point getPosition () {
        return myPosition;
    }

    /**
     * Returns current HP value.
     * @return myHP
     */
    public int getHP () {
        return myHP;
    }

    /**
     * Returns list of sprite types that current sprite can collide with.
     * @return myCollidableTypes
     */
    public Set<Class> getCollidableTypes () {
        return myCollidableTypes;
    }

    @Override
    public boolean isValid () {
        return getHP() > 0;
    }

    protected boolean isCollidableWith (Sprite s) {
        for (Class c : myCollidableTypes) {
            if (c.isInstance(s)) { return true; }
        }
        return false;
    }

    private void initSprite () {
        ImageIcon ii = new ImageIcon(this.getClass().getResource(myImageLoc));
        myImage = ii.getImage();
        myWidth = myImage.getWidth(null);
        myHeight = myImage.getHeight(null);
        myPosition = DEFAULT_POSITION;
        myHP = DEFAULT_HP;
        myCollidableTypes = new HashSet<Class>();
    }
}
